package com.lucien.Stack;

public class Calculator {
    public static void main(String[] args) {
        String expression = "30+2*6-2";
        //创建连个栈
        ArrayStack1 numStack = new ArrayStack1(10);//数栈
        ArrayStack1 operStack = new ArrayStack1(10);//符号栈
        //定义相关变量
        int index=0;//用于扫描
        int num1=0;
        int num2=0;
        int oper=0;
        int res=0;
        char ch = ' ';//将每次扫描得到的char存到ch中
        String keepNum = "";//用于拼接
        //开始while循环扫描expression
        while (true){
            ch = expression.substring(index,index+1).charAt(0);//依次得到每一个字符
            if (operStack.isOper(ch)){//是运算符
                if(!operStack.isEmpty()){//判断当前符号栈是否为空
                    /** 如果符号栈中有符号则进行比较，如果当前操作符的优先级小于或等于栈中的操作符，
                     * 就需要从数栈中pop出两个数，符号栈中pop出一个符号，进行运算，得到结果，入数栈，当前符号入符号栈
                     */
                    if (operStack.priority(ch) <= operStack.priority(operStack.peek())){
                        num1 = numStack.pop();
                        num2 = numStack.pop();
                        oper = operStack.pop();
                        res = numStack.cal(num1,num2,oper);
                        numStack.push(res);//把运算结果存入数栈
                        operStack.push(ch);//把运算符号存入符号栈
                    }else {
                        operStack.push(ch);//如果当前操作符的优先级大于栈中的操作符,直接入栈
                    }
                }else{//如果为空直接入符号栈
                        operStack.push(ch);
                }
            }
//            下面方法含bug：无法存入多位数字
//            else{//如果为数字，直接入栈
//                numStack.push(ch - 48);
//            }
            /**  当处理多位数时，需要向expression表达式的后面在看一位，
             *   如果数字就扫描，是符号则入栈。因此需要定义一个变量用于拼接
             */
            else {
                keepNum  += ch;
                if (index == expression.length()-1){
                    numStack.push(Integer.parseInt(keepNum));
                }else if (operStack.isOper(expression.substring(index+1,index+2).charAt(0))){
                    numStack.push(Integer.parseInt(keepNum));
                    keepNum="";//必循将keepNum清空
                }
            }

            index++;//让index++，判断是否到expression最后
            if (index >= expression.length()){
                break;
            }
        }

        //当扫描完后，就顺序从 数栈和符号栈pop出数据进行计算
        while (true){
            //如果符号栈为空，则计算到最后的结果，此时数栈只有一个数字就是结果
            if (operStack.isEmpty()){
                break;
            }
            num1 = numStack.pop();
            num2 = numStack.pop();
            oper = operStack.pop();
            res = numStack.cal(num1,num2,oper);
            numStack.push(res);//把运算结果存入数栈
        }
        int res2 = numStack.pop();
        System.out.printf("表达式%s=%d",expression,res2);
    }
}

//定义一个 ArrayStack 表示栈
class ArrayStack1{
    private int maxsize;//栈的最大值
    private int [] stack;//数组  数据存放在该数组
    private int top = -1;//栈顶 初始值为-1

    public ArrayStack1(int maxsize){
        this.maxsize = maxsize;
        stack = new int [this.maxsize];
    }

    //判断栈是否满
    public boolean isFull(){
        return top == maxsize-1;
    }

    //判断栈是否空
    public boolean isEmpty(){
        return top == -1;
    }

    //入栈push
    public  void push(int value){
        if (isFull()){
            System.out.println("栈满");
            return;
        }
        top++;
        stack[top] = value;
    }

    //出栈pop
    public int pop(){
        if (isEmpty()){
            throw new RuntimeException("栈空，没有数据");
        }
        int value = stack[top];
        top--;
        return value;
    }

    //显示栈
    public void list(){
        if (isEmpty()){
            System.out.println("栈空，没有数据");
            return;
        }
        //需要从栈顶开始显示数据
        for (int i = top; i >=0 ; i--) {
            System.out.printf("stack[%d] = %d\n",i,stack[i]);
        }
    }

    //返回栈顶的值，但不是出栈
    public int peek(){
        return stack[top];
    }
    /**
     * 返回运算符的优先级，自己来确定，优先级使用数字表示
     * 数字越大，优先级越高
     * 目前表达式只有 +，-，*，/
     */
     public int priority(int oper){
        if (oper == '*' || oper == '/'){
            return 1;
        } else if (oper == '+' || oper == '-') {
            return 0;
        }else {
            return -1;
        }
     }

     //判断是否是运算符
    public boolean isOper(char val){
         return val=='+' || val=='-' || val=='*' || val=='/';
    }

    //计算方法
    public int cal(int num1,int num2,int oper){
        int res = 0;//存放结果
        switch (oper){
            case '+':
                res = num1 + num2;
                break;
            case '-':
                res = num2 - num1;
                break;
            case '*':
                res = num1 * num2;
                break;
            case '/':
                res = num2 / num1;
                break;
        }
        return res;
    }
}
